import axios from 'axios'
import Cookies from 'js-cookie'
import qs from 'qs'
import { showFailToast, showLoadingToast } from 'vant'
import router from '@/router'
import { SUCCESS_CODE, INVALID_LOGIN_CODE, INVALID_LOGIN_URL } from '@/constants'

const service = axios.create({
  // baseURL: JS_CONTEXT.BASE_URL
})
// 请求拦截器
service.interceptors.request.use(config => {
  return config
})

// 响应拦截器
axios.interceptors.response.use(async res => {
  const r = res.data
  const returnResult = {
    ...res,
    data: r
  }
  return r.code === INVALID_LOGIN_CODE ? { invalidLogin: true, message: returnResult.message } : returnResult
})

export function myAjax ({
  url,
  data = {},
  method = 'post',
  postParamsField = 'landmarkInfoBean', // 参数在params中还一层的包裹，只针对post非文件上传
  loading = false, // 是否显示loading
  loadingText = '正在加载', // 显示的loading文字
  showErrorMessageBox = true, // 是否非SUCCESS_CODE状态时直接报错
  errorMessageBoxUseHtml = false, // 这个提示是否用html格式
  timeout = 0,
  // responseType 默认是json
  // axios允许值 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType = 'json',
  headers = {},
  isFormData = false, // 是不是formData，该方法只适用于post
  withCredentials = false, // 表示跨域请求时是否需要使用凭证
  onUploadProgress = null, // 上传进度函数
  onDownloadProgress = null, // 下载进度函数
  cancelToken = null // 取消ajax请求，
  // 取消请参考 http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88
}) {
  url = window.APP_CONFIG.BASE_URL + url
  // 设置请求头
  const defaultHeaders = {
    token: Cookies.get('token'),
    // 'Content-Type': 'application/json',
    ...headers
  }
  // 请求axios配置项
  const axiosOption = {
    url,
    method,
    timeout,
    responseType,
    withCredentials,
    headers: defaultHeaders,
    cancelToken,
    ...setAxiosParams(method, data, isFormData, postParamsField)
  }
  if (onDownloadProgress) axiosOption.onDownloadProgress = onDownloadProgress
  if (onUploadProgress) axiosOption.onUploadProgress = onUploadProgress
  let loadingInstance = null
  if (loading) {
    loadingInstance = showLoadingToast({
      message: loadingText,
      forbidClick: true,
      overlay: true,
      duration: 0,
      loadingType: 'spinner'
    })
  }
  return service(axiosOption).then(res => {
    // blob是需要获取文件名的，一般的文件名放到了响应头中
    if (res) {
      // 如果登录失效后
      if (res?.data?.statusCode === INVALID_LOGIN_CODE) {
        setFailToast('登录失效，请重新登录')
        router.push({ path: INVALID_LOGIN_URL })
        return res
      }
      // 全局统一接口错误提示
      if (responseType !== 'blob' && res.data && res.data.statusCode !== SUCCESS_CODE && showErrorMessageBox) {
        setFailToast(res.data.message)
      }
      return responseType === 'blob' ? { data: res.data, headers: res.headers } : res.data
    }
  }).catch(function (err) {
    const response = err.response || { data: {} }
    const msg = response.data.msg || response.data.message || '请求失败'
    setFailToast(msg)
    return Promise.reject(err)
  }).finally(() => {
    if (loadingInstance) {
      loadingInstance.close()
    }
  })
}

/**
 * 设置ajax请求的参数处理
 * @param method 请求方法
 * @param data 请求参数
 * @param isFormData 是不是FormData数据
 * @param paramsField 参数在params中还一层的包裹，只针对post非文件上传
 * **/
const setAxiosParams = (method, data, isFormData, paramsField) => {
  // Cookies.set('unionId', 'oFt4Z6MD0eDKZpLPHtp2ahuhGxik')
  const funionId = Cookies.get('unionId') || ''
  const option = {}
  if (method === 'get') {
    option.params = { funionId, ...data }
  } else if (method === 'post' && !isFormData) {
    let params = {}
    if (paramsField) {
      params[paramsField] = {
        ...data,
        funionId
      }
    } else {
      params = {
        ...data
      }
    }
    // 这里的数据默认是对象，对象是需要进行序列化的，请根据后台实际情况修改
    option.data = {
      params: JSON.stringify(params)
    }
    option.transformRequest = [function (d) {
      return qs.stringify(d)
      // return JSON.stringify(d)
    }]
  } else if (isFormData) {
    const files = { funionId, ...data }
    // 这里默认你传的是普通的 plain object
    // 此处对plain object进行formData化
    const formData = new FormData()
    for (const k in files) {
      formData.append(k, files[k])
    }
    option.data = formData
  }
  return option
}

const setFailToast = (msg) => {
  setTimeout(() => {
    showFailToast(msg)
  }, 500)
}
